import 'dart:async';
import 'dart:convert';
import 'dart:ui' as ui;
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:amap_flutter_map/amap_flutter_map.dart';
import 'package:amap_flutter_location/amap_flutter_location.dart';
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:amap_flutter_location/amap_location_option.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:xiaofanshu_flutter/static/custom_code.dart';
import 'package:xiaofanshu_flutter/config/amap_config.dart';
import 'package:xiaofanshu_flutter/model/response.dart';
import 'package:xiaofanshu_flutter/model/user.dart';
import 'package:xiaofanshu_flutter/static/default_data.dart';
import 'package:xiaofanshu_flutter/apis/app.dart';
import 'package:xiaofanshu_flutter/utils/snackbar_util.dart';
import 'package:xiaofanshu_flutter/utils/store_util.dart';

class OneRouteMapController extends GetxController {
  // 地图相关
  var currentZoom = 15.0.obs;
  var clusterThreshold = 13.0.obs;
  var showFilterPopup = false.obs;
  var showStoryPreview = false.obs;
  var currentStoryIndex = 0.obs;
  var isLocationInitialized = false.obs;
  var hasMovedToLocation = false.obs;
  var userInfo = DefaultData.user.obs;
  // 聚合相关参数
  var currentBounds = Rx<Map<String, double>?>(null); // 当前地图边界
  var isClusterMode = false.obs; // 是否处于聚合模式
  static const double clusterZoomThreshold = 13.0; // 聚合模式缩放阈值
  Timer? _loadDataTimer; // 防抖定时器
  
  // 高德地图相关
  AMapController? mapController;
  AMapFlutterLocation? locationPlugin;
  StreamSubscription<Map<String, Object>>? locationSubscription;
  var currentLocation = Rxn<LatLng>();
  var cameraPosition = Rxn<CameraPosition>();
  var markers = <Marker>[].obs;
  var polylines = <Polyline>[].obs;  // 路线
  var isInitComplete = false.obs;  // 初始化完成标志位

  // 故事钉数据
  var storyPins = <StoryPin>[].obs;
  var filteredPins = <StoryPin>[].obs;

  // 分类数据
  var categories = <Map<String, dynamic>>[].obs; // 存储从API获取的分类数据
  var selectedCategories = <String, bool>{}.obs; // 动态生成的选中状态
  var showOfficialOnly = false.obs;

  // 用户筛选
  var nicknameFilter = ''.obs;

  @override
  void onInit() {
    super.onInit();
    // 初始化用户信息
    _initUserInfo();
    // 异步初始化定位，不阻塞UI
    _initLocation();
  }
  
  // 初始化用户信息
  Future<void> _initUserInfo() async {
    String? userInfoStr = await readData('userInfo');
    if (userInfoStr != null && userInfoStr.isNotEmpty) {
      try {
        userInfo.value = User.fromJson(jsonDecode(userInfoStr));
      } catch (e) {
        userInfo.value = DefaultData.user;
      }
    } else {
      userInfo.value = DefaultData.user;
    }
  }

  @override
  void onClose() {
    _loadDataTimer?.cancel();
    locationSubscription?.cancel();
    locationPlugin?.destroy();
    super.onClose();
  }

  Future<void> _initLocation() async {
    Get.log('StoryMapController开始初始化定位');
    
    // 设置API密钥
    AMapFlutterLocation.setApiKey(AMapConfig.androidKey, AMapConfig.iosKey);
    Get.log('API密钥已设置');
    
    // 设置隐私合规
    AMapFlutterLocation.updatePrivacyShow(true, true);
    AMapFlutterLocation.updatePrivacyAgree(true);
    Get.log('隐私合规已设置');
    
    // 请求定位权限
    bool hasPermission = await requestLocationPermission();
    Get.log('定位权限请求结果: $hasPermission');
    
    if (!hasPermission) {
      Get.log('定位权限未授予，使用默认位置');
      isLocationInitialized.value = true;
      return;
    }
    
    // 实例化定位插件 - 参考LocationController的实现
    locationPlugin = AMapFlutterLocation();
    Get.log('定位插件已实例化');
    
    // 设置定位监听 - 参考LocationController的实现，先设置监听
    locationSubscription = locationPlugin!.onLocationChanged().listen((Map<String, Object> result) async {
      Get.log('收到定位回调: $result');
      
      // 如果已经移动过，则直接返回
      if (hasMovedToLocation.value) {
        Get.log('已经移动过地图，跳过处理');
        return;
      }
      
      try {
        // 检查是否有有效的位置数据
        if (result['latitude'] == null || result['longitude'] == null) {
          Get.log('定位数据无效: lat=${result['latitude']}, lng=${result['longitude']}');
          return;
        }
        
        double lat = double.parse(result['latitude'].toString());
        double lng = double.parse(result['longitude'].toString());
        
        // 检查是否为0.0,0.0的无效位置
        if (lat == 0.0 && lng == 0.0) {
          Get.log('收到无效位置 (0.0, 0.0)，跳过处理');
          return;
        }
        
        currentLocation.value = LatLng(lat, lng);
        cameraPosition.value = CameraPosition(
          target: currentLocation.value!,
          zoom: currentZoom.value,
        );
        Get.log('当前位置更新为: ${currentLocation.value}');
        
        // 只在第一次获取到有效位置时移动地图
        if (mapController != null && currentLocation.value != null) {
          mapController?.moveCamera(
            CameraUpdate.newLatLngZoom(currentLocation.value!, currentZoom.value),
          );
          hasMovedToLocation.value = true;
          Get.log('地图已移动到当前位置');
        } else {
          // mapController还未初始化，记录位置待后续使用
          Get.log('mapController还未初始化，位置数据已保存，待地图初始化后自动移动');
          // 此时不设置hasMovedToLocation，保持为false，待地图初始化后自动移动
        }
      } catch (e) {
        Get.log('处理定位结果出错: $e');
      }
    });
    
    Get.log('定位监听已设置');
    
    // 设置定位参数 - 在设置监听之后，参考LocationController的实现
    _setLocationOption();
    Get.log('定位参数已设置');
    
    isLocationInitialized.value = true;
    
    // 开始定位 - 参考LocationController的实现
    try {
      locationPlugin?.startLocation();
      Get.log('开始定位');
    } catch (e) {
      Get.log('启动定位服务出错: $e，使用默认位置');
      // 如果启动失败，使用默认位置
      currentLocation.value = LatLng(39.9042, 116.4074); // 北京天安门
      cameraPosition.value = CameraPosition(
        target: currentLocation.value!,
        zoom: currentZoom.value,
      );
      isLocationInitialized.value = true;
      isInitComplete.value = true;
      // await _loadInitialData();
    }
    
    // 标记初始化完成
    isInitComplete.value = true;
    Get.log('定位初始化完成，isInitComplete=${isInitComplete.value}');
    
    // 初始化完成后加载数据
    // await _loadInitialData();
  }
  
  // 请求定位权限
  Future<bool> requestLocationPermission() async {
    var status = await Permission.location.status;
    if (status == PermissionStatus.granted) {
      return true;
    } else {
      status = await Permission.location.request();
      return status == PermissionStatus.granted;
    }
  }

  // 设置定位参数 - 参考LocationController的实现
  void _setLocationOption() {
    AMapLocationOption locationOption = AMapLocationOption();

    ///是否单次定位
    locationOption.onceLocation = true; // 单次定位获取当前位置

    ///是否需要返回逆地理信息
    locationOption.needAddress = true;

    ///逆地理信息的语言类型
    locationOption.geoLanguage = GeoLanguage.DEFAULT;

    locationOption.desiredLocationAccuracyAuthorizationMode =
        AMapLocationAccuracyAuthorizationMode.ReduceAccuracy;

    locationOption.fullAccuracyPurposeKey = "AMapLocationScene";

    ///设置Android端连续定位的定位间隔
    locationOption.locationInterval = 2000;

    ///设置Android端的定位模式<br>
    ///可选值：<br>
    ///<li>[AMapLocationMode.Battery_Saving]</li>
    ///<li>[AMapLocationMode.Device_Sensors]</li>
    ///<li>[AMapLocationMode.Height_Accuracy]</li>
    locationOption.locationMode = AMapLocationMode.Hight_Accuracy;

    ///设置iOS端的定位最小更新距离<br>
    locationOption.distanceFilter = -1;

    ///设置iOS端期望的定位精度
    /// 可选值：<br>
    /// <li>[DesiredAccuracy.Best] 最高精度</li>
    /// <li>[DesiredAccuratForNavigation] 适用于导航场景的高精度 </li>
    /// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
    /// <li>[DesiredAccuracy.Kilometer] 1000米</li>
    /// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
    locationOption.desiredAccuracy = DesiredAccuracy.Best;

    ///设置iOS端是否允许系统暂停定位
    locationOption.pausesLocationUpdatesAutomatically = false;

    ///将定位参数设置给定位插件
    locationPlugin!.setLocationOption(locationOption);
  }

  // Future<void> _loadStoryPins() async {
  //   try {
  //     // 模拟从后端获取数据
  //     // 实际项目中应该调用API获取真实数据
  //     // var response = await Request.get('/story/pins');
  //     // if (response.statusCode == 200) {
  //     //   var data = ResponseModel.fromJson(json.decode(response.body));
  //     //   if (data.code == 200) {
  //     //     // 解析故事钉数据
  //     //     storyPins.value = _parseStoryPins(data.data);
  //     //     _updateFilteredPins();
  //     //     _updateMarkers();
  //     //   }
  //     // } else {
  //     //   // 使用模拟数据
  //     //   _loadMockData();
  //     // }
      
  //     // 暂时使用模拟数据
  //     _loadMockData();
  //   } catch (e) {
  //     // 使用模拟数据
  //     _loadMockData();
  //   }
  // }

  // 加载路线详情数据
  Future<void> loadRouteDetail(int routeId) async {
    try {
      Get.log('开始加载路线详情，routeId: $routeId');

      // 调用路线详情API
      var response = await NoteApi.getRouteById(
        routeId: routeId,
        currentUserId: null, // 暂时不传当前用户ID
      );

      if (response.code == StatusCode.getSuccess && response.data != null) {
        var routeData = response.data;
        Get.log('路线详情加载成功: ${routeData.toString()}');

        // 清空现有数据
        storyPins.clear();
        filteredPins.clear();
        markers.clear();
        polylines.clear();

        // 处理路线节点数据
        var nodes = routeData['nodes'] as List<dynamic>? ?? [];

        List<StoryPin> routePins = [];
        for (var node in nodes) {
          // 使用节点的自定义信息创建故事钉
          StoryPin pin = StoryPin(
            id: node['notesId']?.toString() ?? '',
            title: node['customTitle'] ?? '路线节点',
            content: node['customDescription'] ?? '',
            lat: node['notes']['latitude']?.toDouble() ?? 0.0,
            lng: node['notes']['longitude']?.toDouble() ?? 0.0,
            type: node['notes']['belongCategoryName']?.toString() ?? '',
            noteType: 0,
            isOfficial: false,
            imageUrls: [],
            author: routeData['creatorName'] ?? '',
            likes: 0,
            authorAvatar: null,
            authorId: routeData['userId']?.toString(),
          );

          routePins.add(pin);
        }

        // 更新数据
        storyPins.addAll(routePins);
        filteredPins.addAll(routePins);

        // 更新地图标记
        await updateMarkers();

        // 创建路线连接线
        await createRoutePolylines(routePins, routeData);

        // 调整地图视角以包含整个路线
        if (routePins.isNotEmpty) {
          await _adjustCameraToFitRoute(routePins);
        }

      } else {
        Get.snackbar('错误', response.msg.isEmpty ? '获取路线详情失败' : response.msg);
      }

    } catch (e) {
      Get.log('加载路线详情失败: $e');
      Get.snackbar('错误', '获取路线详情失败：$e');
    }
  }

  // 创建路线连接线
  Future<void> createRoutePolylines(List<StoryPin> routePins, Map<String, dynamic> routeData) async {
    if (routePins.length < 2) {
      Get.log('路线节点少于2个，无需创建连接线');
      return;
    }

    try {
      // 获取路线颜色，默认为美观的渐变色
      String routeColor = routeData['routeColor']?.toString() ?? '#FF5722';
      int lineWidth = routeData['lineWidth'] ?? 6;
      
      // 转换颜色格式
      Color lineColor = _parseColorFromHex(routeColor);
      
      // 创建路线点列表
      List<LatLng> routePoints = [];
      for (int i = 0; i < routePins.length; i++) {
        var pin = routePins[i];
        if (pin.lat != 0.0 && pin.lng != 0.0) {
          routePoints.add(LatLng(pin.lat, pin.lng));
        }
      }

      if (routePoints.length < 2) {
        Get.log('有效路线点少于2个，无需创建连接线');
        return;
      }

      // 创建渐变色路线效果
      List<Polyline> routePolylines = _createGradientPolylines(routePoints, lineColor, lineWidth);

      // 更新polylines
      polylines.clear();
      polylines.addAll(routePolylines);

      Get.log('路线连接线创建成功，共${routePoints.length}个点');
      
    } catch (e) {
      Get.log('创建路线连接线失败: $e');
    }
  }

  // 解析十六进制颜色
  Color _parseColorFromHex(String hexColor) {
    try {
      String colorStr = hexColor.replaceAll('#', '');
      if (colorStr.length == 6) {
        colorStr = 'FF$colorStr'; // 添加透明度
      }
      return Color(int.parse(colorStr, radix: 16));
    } catch (e) {
      // 默认颜色：美观的橙红色
      return const Color(0xFFFF5722);
    }
  }

  // 创建美观的渐变色路线
  List<Polyline> _createGradientPolylines(List<LatLng> routePoints, Color baseColor, int lineWidth) {
    List<Polyline> polylines = [];
    
    // 首先添加阴影线（更粗、更淡）
    Polyline shadowLine = Polyline(
      points: routePoints,
      width: (lineWidth + 6).toDouble(),
      color: Colors.black.withOpacity(0.15),
    );
    polylines.add(shadowLine);
    
    // 主路线（分段创建，每段颜色略有不同，形成动态效果）
    for (int i = 0; i < routePoints.length - 1; i++) {
      double progress = i / (routePoints.length - 1);
      
      // 基于进度调整颜色亮度，创建渐变效果
      Color segmentColor = Color.lerp(
        baseColor,
        baseColor.withOpacity(0.8),
        (progress * 0.3).clamp(0.0, 1.0),
      ) ?? baseColor;
      
      Polyline segment = Polyline(
        points: [routePoints[i], routePoints[i + 1]],
        width: lineWidth.toDouble(),
        color: segmentColor,
      );
      polylines.add(segment);
    }
    
    return polylines;
  }

  // 调整相机位置以适应整个路线
  Future<void> _adjustCameraToFitRoute(List<StoryPin> routePins) async {
    if (routePins.isEmpty || mapController == null) return;

    try {
      // 计算路线的边界
      double minLat = routePins.first.lat;
      double maxLat = routePins.first.lat;
      double minLng = routePins.first.lng;
      double maxLng = routePins.first.lng;

      for (var pin in routePins) {
        if (pin.lat < minLat) minLat = pin.lat;
        if (pin.lat > maxLat) maxLat = pin.lat;
        if (pin.lng < minLng) minLng = pin.lng;
        if (pin.lng > maxLng) maxLng = pin.lng;
      }

      // 添加一些边距
      double latPadding = (maxLat - minLat) * 0.2;
      double lngPadding = (maxLng - minLng) * 0.2;

      minLat -= latPadding;
      maxLat += latPadding;
      minLng -= lngPadding;
      maxLng += lngPadding;

      // 创建边界
      LatLngBounds bounds = LatLngBounds(
        southwest: LatLng(minLat, minLng),
        northeast: LatLng(maxLat, maxLng),
      );

      // 移动相机到边界
      await mapController!.moveCamera(CameraUpdate.newLatLngBounds(bounds, 100.0));
      
      Get.log('相机已调整以适应路线：边界 ${bounds.southwest} 到 ${bounds.northeast}');
    } catch (e) {
      Get.log('调整相机位置失败: $e');
      // 降级：移动到第一个点
      if (routePins.isNotEmpty) {
        var firstPin = routePins.first;
        currentLocation.value = LatLng(firstPin.lat, firstPin.lng);
        await mapController!.moveCamera(CameraUpdate.newLatLng(
          LatLng(firstPin.lat, firstPin.lng),
        ));
      }
    }
  }

  // 创建路线节点图标（带序号）
  Future<BitmapDescriptor> _createRouteNodeIcon(StoryPin pin, int index) async {
    try {
      // 计算图标大小
      const double size = 120.0;
      const double iconRadius = size / 2;
      
      // 创建画布
      final ui.PictureRecorder recorder = ui.PictureRecorder();
      final Canvas canvas = Canvas(recorder);
      
      // 定义颜色
      Color primaryColor = const Color(0xFFFF5722); // 主色
      Color textColor = Colors.white;
      Color shadowColor = Colors.black.withOpacity(0.3);
      
      // 绘制阴影
      final shadowPaint = Paint()
        ..color = shadowColor
        ..maskFilter = const ui.MaskFilter.blur(ui.BlurStyle.normal, 6);
      canvas.drawCircle(
        Offset(iconRadius + 3, iconRadius + 3), 
        iconRadius - 8, 
        shadowPaint
      );
      
      // 绘制外圆（白色边框）
      final borderPaint = Paint()
        ..color = Colors.white
        ..style = ui.PaintingStyle.fill;
      canvas.drawCircle(Offset(iconRadius, iconRadius), iconRadius - 5, borderPaint);
      
      // 绘制内圆（主色）
      final circlePaint = Paint()
        ..color = primaryColor
        ..style = ui.PaintingStyle.fill;
      canvas.drawCircle(Offset(iconRadius, iconRadius), iconRadius - 12, circlePaint);
      
      // 绘制序号文字
      final textPainter = TextPainter(
        text: TextSpan(
          text: index.toString(),
          style: TextStyle(
            color: textColor,
            fontSize: index < 10 ? 32 : 28, // 两位数字体稍小
            fontWeight: FontWeight.bold,
          ),
        ),
        textDirection: ui.TextDirection.ltr,
      );
      
      textPainter.layout();
      final textOffset = Offset(
        iconRadius - textPainter.width / 2,
        iconRadius - textPainter.height / 2,
      );
      textPainter.paint(canvas, textOffset);
      
      // 转换为图片
      final ui.Picture picture = recorder.endRecording();
      final ui.Image image = await picture.toImage(size.toInt(), size.toInt());
      final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
      
      if (byteData != null) {
        return BitmapDescriptor.fromBytes(byteData.buffer.asUint8List());
      } else {
        return BitmapDescriptor.defaultMarker;
      }
    } catch (e) {
      Get.log('创建路线节点图标失败: $e');
      return BitmapDescriptor.defaultMarker;
    }
  }

  Future<void> _loadMockData() async {
    storyPins.value = [
      StoryPin(
        id: '1',
        title: '这家隐藏咖啡馆也太可了吧！',
        content: '偶然发现的小众咖啡馆，环境超级温馨，墙上全是复古装饰，每个角落都很适合拍照，重点是他家的脏脏包真的绝了！松软的面包...',
        lat: 39.9042,
        lng: 116.4074,
        type: 'coffee',
        noteType: 0,
        isOfficial: true,
        imageUrls: [
          'https://example.com/coffee1.jpg',
          'https://example.com/coffee2.jpg',
          'https://example.com/coffee3.jpg',
        ],
        author: '小红薯123',
        likes: 2300,
      ),
      StoryPin(
        id: '2',
        title: '北京胡同里的秘密花园',
        content: '藏在老胡同里的小花园，种满了各种花草，阳光洒下来的时候特别美，简直是城市中的世外桃源...',
        lat: 39.9142,
        lng: 116.4274,
        type: 'travel',
        noteType: 0,
        isOfficial: false,
        imageUrls: [
          'https://example.com/garden1.jpg',
        ],
        author: '摄影师小王',
        likes: 1500,
      ),
      StoryPin(
        id: '3',
        title: '深夜食堂推荐',
        content: '这家深夜食堂的拉面真的绝了！汤底浓郁，叉烧入口即化，每次加班后必来打卡...',
        lat: 39.9242,
        lng: 116.3974,
        type: 'food',
        noteType: 0,
        isOfficial: true,
        imageUrls: [
          'https://example.com/ramen1.jpg',
          'https://example.com/ramen2.jpg',
        ],
        author: '美食达人',
        likes: 3200,
      ),
    ];
    // _updateFilteredPins();
    await updateMarkers();
  }

  List<StoryPin> _parseStoryPins(dynamic data) {
    // 实际项目中解析后端返回的故事钉数据
    return [];
  }

  // void _updateFilteredPins() {
  //   filteredPins.value = storyPins.where((pin) {
  //     if (showOfficialOnly.value && !pin.isOfficial) return false;
  //
  //     // 将故事钉的类型转换为小写，与分类名称匹配
  //     String pinType = pin.type.toLowerCase();
  //
  //     // 检查是否有匹配的分类
  //     bool hasMatchingCategory = selectedCategories.containsKey(pinType) &&
  //                                (selectedCategories[pinType] ?? false);
  //
  //     // 如果没有直接匹配，尝试模糊匹配
  //     if (!hasMatchingCategory) {
  //       for (var category in categories) {
  //         String categoryName = category['categoryName']?.toString().toLowerCase() ?? '';
  //         if (categoryName.contains(pinType) || pinType.contains(categoryName)) {
  //           hasMatchingCategory = selectedCategories[categoryName] ?? false;
  //           break;
  //         }
  //       }
  //     }
  //
  //     return hasMatchingCategory;
  //   }).toList();
  // }

  Future<void> updateMarkers() async {
    markers.clear();
    List<Marker> newMarkers = [];
    
    for (int i = 0; i < filteredPins.length; i++) {
      var pin = filteredPins[i];
      try {
        // 为路线节点创建带序号的图标
        final icon = await _createRouteNodeIcon(pin, i + 1);
        final marker = Marker(
          position: LatLng(pin.lat, pin.lng),
          icon: icon,
          onTap: (String id) => onMarkerTap(pin),
          infoWindow: InfoWindow(
            title: '${i + 1}. ${pin.title}',
            snippet: pin.content,
          ),
        );
        newMarkers.add(marker);
      } catch (e) {
        Get.log('创建标记失败: ${pin.id}, 错误: $e');
        // 如果创建失败，使用默认图标
        final marker = Marker(
          position: LatLng(pin.lat, pin.lng),
          icon: BitmapDescriptor.defaultMarker,
          onTap: (String id) => onMarkerTap(pin),
        );
        newMarkers.add(marker);
      }
    }
    
    markers.value = newMarkers;
  }

  // 处理地图移动事件，根据缩放级别决定调用哪个API
  void onCameraMove(CameraPosition cameraPosition) {
    // currentZoom.value = cameraPosition.zoom;
    // this.cameraPosition.value = cameraPosition;
    //
    // // 清除之前的定时器
    // _loadDataTimer?.cancel();
    //
    // // 设置新的定时器，防抖500ms
    // _loadDataTimer = Timer(const Duration(milliseconds: 500), () {
    //   // 检查缩放级别是否达到聚合阈值
    //   if (currentZoom.value < clusterZoomThreshold) {
    //     // 聚合模式
    //     if (!isClusterMode.value) {
    //       isClusterMode.value = true;
    //       _loadClusters();
    //     }
    //   } else {
    //     // 普通模式
    //     if (isClusterMode.value) {
    //       isClusterMode.value = false;
    //     }
    //     _loadStoriesWithinBounds();
    //   }
    // });
  }

  // 获取当前地图边界
  String _getCurrentBounds() {
    if (mapController == null) return '';
    
    // 使用相机位置获取当前地图中心点和缩放级别
    final CameraPosition currentCameraPosition = cameraPosition.value ?? CameraPosition(
      target: currentLocation.value ?? const LatLng(39.9042, 116.4074),
      zoom: currentZoom.value,
    );
    
    final LatLng center = currentCameraPosition.target; // 地图中心点经纬度
    final double zoom = currentCameraPosition.zoom; // 地图缩放级别

    // 计算当前缩放级别下，地图窗口对应的经纬度跨度
    // 基于网络地图瓦片系统原理：
    // - zoom=0时，整个地球360度经度，180度纬度
    // - 每增加1级，地图精度提高2倍，显示范围缩小一半
    // - 手机屏幕宽度约360-414逻辑像素，对应实际地图范围需要经验调整
    
    // 基础计算：360度 / (2^zoom) 得到当前级别的基本跨度
    // 然后考虑手机屏幕显示比例和实际视觉效果进行调整
    double baseDelta = 180.0 / (1 << zoom.toInt());  // 基础跨度（半球）
    
    // 经验系数调整：根据实际测试，当系数为0.3时，范围最接近真实可视区域
    // 这个系数考虑了：屏幕像素密度、地图投影变形、用户视觉感受
    double visualScaleFactor = 2;  // 视觉比例系数（原0.5调整为0.3，扩大1.67倍）
    double delta = baseDelta * visualScaleFactor;

    // 计算西南角（左下）和东北角（右上）的坐标
    final LatLng southwest = LatLng(center.latitude - delta, center.longitude - delta);
    final LatLng northeast = LatLng(center.latitude + delta, center.longitude + delta);

    // 构建LatLngBounds对象
    final LatLngBounds bounds = LatLngBounds(southwest: southwest, northeast: northeast);
    
    // 添加调试日志，帮助验证计算结果
    Get.log('地图边界计算 - 中心点: (${center.latitude}, ${center.longitude}), 缩放级别: $zoom, 跨度: ±${delta.toStringAsFixed(6)}°, 范围: ${(delta * 2).toStringAsFixed(6)}°');
    Get.log('地图边界 - 西南: (${southwest.latitude}, ${southwest.longitude}), 东北: (${northeast.latitude}, ${northeast.longitude})');
    
    // 返回格式：minLat,minLng,maxLat,maxLng
    return '${bounds.southwest.latitude},${bounds.southwest.longitude},${bounds.northeast.latitude},${bounds.northeast.longitude}';
  }

  // 调用聚合API
  Future<void> _loadClusters() async {
    try {
      final bounds = _getCurrentBounds();
      if (bounds.isEmpty) return;
      
      // 获取当前选中的分类
      List<String> selectedCategoryList = [];
      selectedCategories.forEach((category, isSelected) {
        if (isSelected) {
          selectedCategoryList.add(category);
        }
      });
      
      // 记录过滤参数
      Get.log('调用getClusters API - 分类: ${selectedCategoryList.join(',')}, 官方: ${showOfficialOnly.value}, 用户: ${nicknameFilter.value}');
      
      final response = await StoryMapApi.getClusters(
        currentZoom.value.toInt(),
        bounds,
        categories: selectedCategoryList.isNotEmpty ? selectedCategoryList : null,
        isOfficial: showOfficialOnly.value ? true : null,
        nickname: nicknameFilter.value.isNotEmpty ? nicknameFilter.value : null,
      );
      
      if (response.code == 200 || response.code == StatusCode.getSuccess) {
        await _parseClusters(response.data);
      }
    } catch (e) {
      Get.log('加载聚合数据失败: $e');
      // 失败时回退到模拟数据
      await _loadMockData();
    }
  }

  // 调用边界内故事API
  Future<void> _loadStoriesWithinBounds() async {
    try {
      final bounds = _getCurrentBounds();
      if (bounds.isEmpty) return;
      
      // 获取当前选中的分类
      List<String> selectedCategoryList = [];
      selectedCategories.forEach((category, isSelected) {
        if (isSelected) {
          selectedCategoryList.add(category);
        }
      });
      
      // 记录过滤参数
      Get.log('调用getStoriesWithinBounds API - 分类: ${selectedCategoryList.join(',')}, 官方: ${showOfficialOnly.value}, 用户: ${nicknameFilter.value}');
      
      final response = await StoryMapApi.getStoriesWithinBounds(
        bounds,
        categories: selectedCategoryList.isNotEmpty ? selectedCategoryList : null,
        isOfficial: showOfficialOnly.value ? true : null,
        nickname: nicknameFilter.value.isNotEmpty ? nicknameFilter.value : null,
      );
      
      if (response.code == 200 || response.code == StatusCode.getSuccess) {
        await _parseStoriesWithinBounds(response.data);
      }
    } catch (e) {
      Get.log('加载边界内故事失败: $e');
      // 失败时回退到模拟数据
      await _loadMockData();
    }
  }

  // 解析聚合数据
  Future<void> _parseClusters(Map<String, dynamic> data) async {
    List<StoryPin> allPins = [];
    
    // 解析聚合点
    if (data['clusters'] != null) {
      for (var cluster in data['clusters']) {
        // 为每个聚合点创建一个代表点
        final position = cluster['position'] as List;
        allPins.add(StoryPin(
          id: cluster['id'],
          title: '聚合地点 (${cluster['count']}个故事)',
          content: '这里有${cluster['count']}个精彩故事等你发现',
          lat: position[1], // 纬度
          lng: position[0], // 经度
          type: 'cluster',
          noteType: 0,
          isOfficial: false,
          imageUrls: [],
          author: '聚合',
          likes: cluster['count'],
        ));
      }
    }
    
    // 解析独立点
    if (data['singlePoints'] != null) {
      for (var point in data['singlePoints']) {
        final position = point['position'] as List;
        allPins.add(StoryPin(
          id: point['id'],
          title: point['name'] ?? '未知地点',
          content: '一个有趣的地方',
          lat: position[1], // 纬度
          lng: position[0], // 经度
          type: 'single',
          noteType: 0,
          isOfficial: false,
          imageUrls: [],
          author: '聚合',
          likes: 1,
        ));
      }
    }
    
    storyPins.value = allPins;
    // 服务器已根据过滤条件返回结果，直接使用，不再进行客户端过滤
    filteredPins.value = allPins;
    
    // 重置故事预览索引，防止越界
    if (currentStoryIndex.value >= filteredPins.length) {
      currentStoryIndex.value = 0;
    }
    
    await updateMarkers();
  }

  // 解析边界内故事数据
  Future<void> _parseStoriesWithinBounds(Map<String, dynamic> data) async {
    // 假设返回的是分页数据，提取内容列表
    List<dynamic> contentList = [];
    if (data['content'] != null) {
      contentList = data['content'];
    } else if (data['records'] != null) {
      contentList = data['records'];
    } else if (data['list'] != null) {
      contentList = data['list'];
    } else {
      // 如果data没有content、records或list字段，可能是其他格式
      Get.log('边界内故事数据格式未知: $data');
      return;
    }
    
    List<StoryPin> allPins = [];
    for (var item in contentList) {
      allPins.add(_parseStoryPin(item));
    }
    
    storyPins.value = allPins;
    // 服务器已根据过滤条件返回结果，直接使用，不再进行客户端过滤
    filteredPins.value = allPins;
    
    // 重置故事预览索引，防止越界
    if (currentStoryIndex.value >= filteredPins.length) {
      currentStoryIndex.value = 0;
    }
    
    await updateMarkers();
  }

  // 解析单个故事点
  StoryPin _parseStoryPin(Map<String, dynamic> item) {
    return StoryPin(
      id: item['id'].toString(),
      title: item['title'] ?? '无标题',
      content: item['content'] ?? '暂无描述',
      lat: item['latitude']?.toDouble() ?? 0.0,
      lng: item['longitude']?.toDouble() ?? 0.0,
      type: item['belongCategoryName'] ?? 'unknown',
      noteType: item['notesType']??0,
      isOfficial: item['isOfficial'] ?? false,
      imageUrls: item['imageUrls'] != null ? List<String>.from(item['imageUrls']) : [],
      authorId: item['belongUserId'] ?? '0',
      author: item['nickname']??'匿名用户',
      likes: item['likes'] ?? 0,
    );
  }

  // 初始化数据加载
  Future<void> _loadInitialData() async {
    // 先加载分类数据
    await _loadCategories();
    
    // 根据当前缩放级别决定加载方式
    if (currentZoom.value < clusterZoomThreshold) {
      await _loadClusters();
    } else {
      await _loadStoriesWithinBounds();
    }
  }

  // 从API获取分类数据
  Future<void> _loadCategories() async {
    try {
      HttpResponse response = await NoteApi.getNoteCategory();
      if (response.code == StatusCode.getSuccess) {
        List<dynamic> categoryList = response.data as List<dynamic>;
        categories.value = categoryList.map((item) => item as Map<String, dynamic>).toList();
        
        // 动态生成选中状态，默认不选中任何分类（查询全部）
        Map<String, bool> initialSelection = {};
        for (var category in categories) {
          String categoryKey = category['categoryName']?.toString().toLowerCase() ?? 'unknown';
          initialSelection[categoryKey] = false; // 默认不选中
        }
        selectedCategories.value = initialSelection;
        
        Get.log('成功加载分类数据: ${categories.length}个分类');
      } else {
        Get.log('获取分类数据失败: ${response.msg}');
        _useDefaultCategories();
      }
    } catch (e) {
      Get.log('获取分类数据出错: $e');
      _useDefaultCategories();
    }
  }

  // 使用默认分类
  void _useDefaultCategories() {
    categories.value = [
      {'id': 1, 'categoryName': '旅行', 'categorySort': 1},
      {'id': 2, 'categoryName': '美食', 'categorySort': 2},
      {'id': 3, 'categoryName': '咖啡', 'categorySort': 3},
      {'id': 4, 'categoryName': '购物', 'categorySort': 4},
      {'id': 5, 'categoryName': '景点', 'categorySort': 5},
      {'id': 6, 'categoryName': '酒店', 'categorySort': 6},
    ];
    
    selectedCategories.value = {
      'travel': false,
      'food': false,
      'coffee': false,
      'shopping': false,
      'attraction': false,
      'hotel': false,
    };
  }

  Future<BitmapDescriptor> _createMarkerIcon(StoryPin pin) async {
    // 根据pin类型返回不同的图标
    try {
      Get.log('创建标记图标，pin类型: ${pin.type}, ID: ${pin.id}, 标题: ${pin.title}');
      
      // 如果是聚合点，创建动态图标
      if (pin.type == 'cluster') {
        return await _createClusterIcon(pin);
      }else if(pin.type == 'single'){
        return await _createClusterIcon(pin);
      }
      
      // 定义类型到图片文件的映射
      Map<String, String> iconMapping = {
        '默认': 'images/yule.jpg',      // 未知 -> 大师篮球
        '搞笑': 'images/gaoxiao.jpg',
        '鬼故事': 'images/ggs.jpg',
        '记忆': 'images/jiyi.jpg',
        '旅游': 'images/lvyou.jpg',
        '摄影': 'images/sheying.jpg',
        '寻宝': 'images/xunbao.jpg',
        '娱乐': 'images/yule.jpg',
        '历史': 'images/lishi.jpg',
        '艺术': 'images/yishu.jpg',
      };
      
      // 根据pin类型获取对应的图片路径，如果没有映射则使用默认图片
      String imagePath = iconMapping[pin.type] ?? 'images/yule.jpeg';
      Get.log('选择的图片路径: $imagePath');
      
      // 使用自定义图标 - 使用异步方式创建
      BitmapDescriptor icon = await BitmapDescriptor.fromAssetImage(
        const ImageConfiguration(size: Size(68, 68)),
        imagePath,
      );
      
      Get.log('图标创建成功: ${pin.type}');
      return icon;
    } catch (e) {
      Get.log('加载自定义标记图标失败: ${pin.type}, 错误: $e');
      // 如果加载失败，返回默认图标
      return BitmapDescriptor.defaultMarker;
    }
  }

  // 创建聚合图标
  Future<BitmapDescriptor> _createClusterIcon(StoryPin pin) async {
    try {
      // 获取聚合数量
      int count = pin.likes;
      // 如果超过99，显示99+
      String displayText = count > 99 ? '99+' : count.toString();
      
      // 创建画布
      final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
      final ui.Canvas canvas = ui.Canvas(pictureRecorder);
      
      // 设置图标大小
      const double size = 80.0;
      
      // 绘制圆形背景
      final ui.Paint backgroundPaint = ui.Paint()
        ..color = Colors.red
        ..style = ui.PaintingStyle.fill;
      canvas.drawCircle(const ui.Offset(size/2, size/2), size/2, backgroundPaint);
      
      // 绘制圆形边框
      final ui.Paint borderPaint = ui.Paint()
        ..color = Colors.white
        ..style = ui.PaintingStyle.stroke
        ..strokeWidth = 3;
      canvas.drawCircle(const ui.Offset(size/2, size/2), size/2 - 1.5, borderPaint);
      
      // 绘制数字
      final TextPainter textPainter = TextPainter(
        text: TextSpan(
          text: displayText,
          style: TextStyle(
            color: Colors.white,
            fontSize: count > 99 ? 24 : 28, // 99+ 使用稍小字体
            fontWeight: FontWeight.bold,
          ),
        ),
        textDirection: TextDirection.ltr,
      );
      
      textPainter.layout();
      final Offset textOffset = Offset(
        (size - textPainter.width) / 2,
        (size - textPainter.height) / 2,
      );
      textPainter.paint(canvas, textOffset);
      
      // 生成图片
      final ui.Picture picture = pictureRecorder.endRecording();
      final ui.Image image = await picture.toImage(size.toInt(), size.toInt());
      final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
      
      if (byteData == null) {
        throw Exception('无法生成聚合图标字节数据');
      }
      
      final Uint8List uint8List = byteData.buffer.asUint8List();
      return BitmapDescriptor.fromBytes(uint8List);
    } catch (e) {
      Get.log('创建聚合图标失败: $e');
      // 如果创建失败，返回默认聚合图标
      return await BitmapDescriptor.fromAssetImage(
        const ImageConfiguration(size: Size(48, 48)),
        'images/rsjy.jpg',
      );
    }
  }

  void onMarkerTap(StoryPin pin) {
    showStoryPreview.value = true;
    int index = filteredPins.indexOf(pin);
    // 确保索引有效，如果找不到则默认为0
    currentStoryIndex.value = index >= 0 ? index : 0;
  }

  /**
   * 地图点击事件处理 - 点击地图时关闭所有弹窗
   */
  void onMapTap(LatLng position) {
    Get.log('地图被点击，关闭所有弹窗');
    // 关闭过滤弹窗
    if (showFilterPopup.value) {
      showFilterPopup.value = false;
    }
    // 关闭故事预览弹窗
    if (showStoryPreview.value) {
      showStoryPreview.value = false;
    }
  }

  /**
   * 地图创建完成回调
   */
  void onMapCreated(AMapController controller) {
    mapController = controller;
    Get.log('地图控制器已初始化完成');
    
    // 检查是否有待处理的位置数据
    if (currentLocation.value != null && !hasMovedToLocation.value) {
      // 延迟一下确保地图完全初始化
      Future.delayed(const Duration(milliseconds: 500), () {
        if (mapController != null && currentLocation.value != null) {
          mapController?.moveCamera(
            CameraUpdate.newLatLngZoom(currentLocation.value!, currentZoom.value),
          );
          hasMovedToLocation.value = true;
          Get.log('地图初始化完成后自动移动到当前位置');
        }
      });
    }
  }

  /**
   * 移动到当前位置
   */
  void moveToCurrentLocation() {
    if (currentLocation.value != null && mapController != null) {
      mapController?.moveCamera(
        CameraUpdate.newLatLngZoom(currentLocation.value!, currentZoom.value),
      );
    }
  }

  void toggleFilterPopup() {
    showFilterPopup.value = !showFilterPopup.value;
  }

  Future<void> toggleCategory(String category) async {
    selectedCategories[category] = !(selectedCategories[category] ?? false);
    // 不再立即过滤，只更新选中状态
    Get.log('切换分类选中状态: $category = ${selectedCategories[category]}');
  }

  // 全选所有分类
  void selectAllCategories() {
    selectedCategories.forEach((key, value) {
      selectedCategories[key] = true;
    });
    Get.log('全选所有分类');
  }

  // 清空所有分类选择
  void clearAllCategories() {
    selectedCategories.forEach((key, value) {
      selectedCategories[key] = false;
    });
    Get.log('清空所有分类选择');
  }

  Future<void> toggleOfficialOnly() async {
    showOfficialOnly.value = !showOfficialOnly.value;
    // 不再立即过滤，只更新选中状态
    Get.log('切换官方认证状态: ${showOfficialOnly.value}');
  }

  // 确认过滤条件并重新加载数据
  Future<void> confirmFilterAndReload() async {
    Get.log('确认过滤条件，重新加载数据');
    
    // 关闭弹窗
    showFilterPopup.value = false;
    
    // 根据当前缩放级别重新加载数据
    if (currentZoom.value < clusterZoomThreshold) {
      // 缩放级别较低时，加载聚合数据
      await _loadClusters();
    } else {
      // 缩放级别较高时，加载详细故事数据
      await _loadStoriesWithinBounds();
    }
  }

  void nextStory() {
    if (filteredPins.isEmpty) return;
    if (currentStoryIndex.value < filteredPins.length - 1) {
      currentStoryIndex.value++;
    } else {
      // 如果已经是最后一个，循环到第一个
      currentStoryIndex.value = 0;
    }
  }

  void previousStory() {
    if (filteredPins.isEmpty) return;
    if (currentStoryIndex.value > 0) {
      currentStoryIndex.value--;
    } else {
      // 如果已经是第一个，循环到最后一个
      currentStoryIndex.value = filteredPins.length - 1;
    }
  }

  void closeStoryPreview() {
    showStoryPreview.value = false;
  }

  void navigateToStoryDetail(StoryPin story) {
    int storyId = int.tryParse(story.id) ?? 0;
    story.noteType == 0
        ? Get.toNamed('/notes/detail/image', arguments: storyId)
        : Get.toNamed('/notes/detail/video', arguments: storyId);
  }

  void navigateToUserProfile(String userId) {
    int userIdInt = int.tryParse(userId) ?? 0;
    Get.toNamed('/other/mine', arguments: userIdInt);
  }

  /// 删除路线
  Future<void> deleteRoute(int routeId) async {
    try {
      // 获取当前用户ID
      String? userIdStr = userInfo.value.id.toString();
      if (userIdStr == null || userIdStr.isEmpty) {
        SnackbarUtil.showError('请先登录');
        return;
      }
      
      int userId = int.tryParse(userIdStr) ?? 0;
      if (userId == 0) {
        SnackbarUtil.showError('用户信息异常');
        return;
      }
      
      // 调用删除API
      HttpResponse response = await NoteApi.deleteRoute(
        routeId: routeId,
        userId: userId,
      );
      
      if (response.code == StatusCode.deleteSuccess) {
        SnackbarUtil.showSuccess('删除成功');
        // 延迟一下再返回，让用户看到成功提示
        await Future.delayed(const Duration(milliseconds: 500));
        Get.back();
      } else {
        SnackbarUtil.showError('删除失败：${response.msg}');
      }
    } catch (e) {
      Get.log('删除路线失败: $e');
      SnackbarUtil.showError('删除失败：$e');
    }
  }
}

class StoryPin {
  final String id;
  final String title;
  final String content;
  final double lat;
  final double lng;
  final String type;
  final int noteType;
  final bool isOfficial;
  final List<String> imageUrls;
  final String author;
  final int likes;
  final String? authorAvatar;
  final String? authorId;

  StoryPin({
    required this.id,
    required this.title,
    required this.content,
    required this.lat,
    required this.lng,
    required this.type,
    required this.noteType,
    required this.isOfficial,
    required this.imageUrls,
    required this.author,
    required this.likes,
    this.authorAvatar,
    this.authorId,
  });
}